iT邦幫忙

2022 iThome 鐵人賽

DAY 14
1
Modern Web

前端蛇行撞牆記系列 第 14

Day14 前端蛇行撞牆記 - 由__proto__串起的原型鏈

  • 分享至 

  • xImage
  •  

前言

以前在看__proto__, prototype都會覺得天啊我不行~~太多看起來很不好理解的東西惹
可是當我查到我參考資料放的第一篇文章Javascripter 必須知道的繼承 prototype, [[prototype]], __proto__
就覺得好像突然懂了什麼?!
其實不過就是 XXX.__proto__ === YYY.prototype 嘛!
什麼意思!!?? 請繼續看下去~

__proto__

當我們在提及使用建構式函式new出來的實例可以直接繼承建構式的prototype,但新出來的實例是如何找到原型prototype的呢?靠的是一個屬性叫做__proto__做的,他可以取回了原型物件內部的prototype當作參考。

__proto__是什麼意思?其實可以把它想成一個取值器, 當呼叫某物件的原型物件方法之後,它會先找自己有沒有這個方法,沒有的話就往上找,也就是說會去參考物件的原型物件prototype。

我們來看個範例:

  1. 建立了一個建構式函式Person,包含一個prototype
  2. 讓nick成為Person的instance
  3. 來看看jade.__proto__是什麼
function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.log = function () {
  console.log(this.name + ", age:" + this.age);
};

var jade = new Person("jade", 18);

// 以下三個結果都一樣
console.log(jade.__proto__); 
// { log: [Function (anonymous)] }
console.log(Object.getPrototypeOf(jade)); 
// { log: [Function (anonymous)] }
console.log(Person.prototype); 
// { log: [Function (anonymous)] }

console.log(jade.__proto__ === Person.prototype); 
// true

結果不論是jade.__proto__還是Person本身的Person.prototype都會回傳function log(),也就是說:

  • __proto__會返回物件所繼承的prototype。
    像是這個樣子 => jade.__proto__ === Person.prototype

到這裡其實就差不多解釋完__proto__的意思,那我們繼續往上連看會到哪裡:

console.log(jade.__proto__.__proto__ === Object.prototype);

// true

現在這個__proto__就會指到原型物件的再上層,也就是Object.prototype

console.log(jade.__proto__.__proto__.__proto__);

// null

再往上一層的話,就到最頂層的null了。

於是這整條由__proto__串接的就是原型鏈

null

Object.prototype

Person.prototype

jade


Object.ceate()如何完成繼承原物件

在上面一個範例可以繼承是因為讓jade物件成為Person的instance,這些是我們自己手動的,突然就好奇像是Object.ceate()是怎麼讓物件繼承原型物件的prototype?

Object.create()的簡單實作:

  1. 先建立了一個空的物件,先叫他新物件。
  2. 設定新物件的prototype 就是傳進去的原型物件 object(第一個參數)
  3. 最後return 新物件。
const newObject = Object.create = function(object) {
 const newOobject = {}
 newOobject.__proto__ = object;
 return newObject;
}
  • 複習一下Object.create()的用法:
Object.create(proto, propertiesObject)

例子:

const jade = {
  name: "Jade",
  age: 28,
  school: "TNUA",
  greet: function () {
    return `here is greet by ${this.name}`;
  },
};

const ann = Object.create(jade);


console.log(ann.__proto__ === jade.prototype);
// true
console.log(ann.__proto__);
// { name: 'Jade', age: 28, school: 'TNUA', greet: [Function: greet] }

在知道了Obejct.create()是如何讓新物件可以繼承原型物件之後,可以看到ann.__proto__會回傳整個jade的property。

因為在Obejct.create()的時候已經讓這新物件的prototype指向整個原型物件了。

ann.__proto__就會是全部原型物件的property { name: 'Jade', age: 28, school: 'TNUA', greet: [Function: greet] }

總結

  • __proto__會指向原型物件的prototype
  • 當呼叫一物件的方法時,會先看自己有沒有這個方法,沒有就往上找,如果都沒有就會報錯,而這個串起連結的過程就是原型鏈。

先這樣拉
明天見~


參考資料:Javascripter 必須知道的繼承 prototype, [[prototype]], __proto__
你所不知道的JS 範疇與closures/this與物件原型 p.184
008天


上一篇
Day13 前端蛇行撞牆記 - Contructor function 建構式函式
下一篇
Day15 前端蛇行撞牆記 - class v.s constructor
系列文
前端蛇行撞牆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

我要留言

立即登入留言